{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [Strict aliasing](https://en.cppreference.com/w/c/language/object.html#:~:text=for%20the%20access.-,Strict%20aliasing,-Given%20an%20object)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在现代 C++ 编译器中，为了提升优化效率，编译器会假设“不同类型的指针不会指向同一块内存”。这条假设就被称为 **Strict Aliasing（严格别名）规则**。如果代码违反了这一假设，编译器的优化可能会导致未定义行为（Undefined Behavior）。\n",
    "\n",
    "通俗地说：除非类型之间有明确的别名关系，否则编译器会认为它们指向的数据互不相关，从而可以放心进行诸如寄存器缓存、指令重排等优化。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## **官方规则概览**\n",
    "\n",
    "标准（C++23 [basic.lval]/11）规定：一个对象可以通过以下类型访问：\n",
    "\n",
    "1. 它的静态类型（original type）。\n",
    "2. 与该类型兼容的 cv-qualified 版本。\n",
    "3. 同样布局（similar type, e.g. `struct` 的标准布局对象）或兼容的联合成员。\n",
    "4. `char`、`unsigned char` 或 `std::byte`。\n",
    "5. `std::byte`（自 C++17 起）。\n",
    "\n",
    "除此之外的类型访问该对象就违反 Strict Aliasing。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## **常见易踩坑示例**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "float f = 1.0f;\n",
    "int* ip = reinterpret_cast<int*>(&f);\n",
    "int value = *ip; // 读取 float 作为 int —— 未定义行为"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "即便这段代码在某些平台似乎可行，编译器也可能进行危险优化，导致不可预测的结果。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## **像素级别：原因与后果**\n",
    "\n",
    "- **原因**：编译器为了获得更激进的优化，假定不同类型的指针不会指向同一对象。\n",
    "- **后果**：如果你强行“跨类型”访问同一片内存，编译器的优化可能让读取写入行为不再符合你的预期。表现为莫名的值改变、分支消失、循环优化出错等。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 什么时候不违反规则？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用 `char` / `unsigned char` / `std::byte`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "float f = 1.0f;\n",
    "unsigned char* cp = reinterpret_cast<unsigned char*>(&f); // 合法\n",
    "for (size_t i = 0; i < sizeof(float); ++i) {\n",
    "    std::printf(\"%02X \", cp[i]);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "标准允许通过这三种类型查看任何对象的字节表示。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用 `std::memcpy` 或 `std::bit_cast`（C++20）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "float f = 1.0f;\n",
    "int value;\n",
    "std::memcpy(&value, &f, sizeof(value)); // 合法拷贝字节"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <bit>\n",
    "float f = 1.0f;\n",
    "int value = std::bit_cast<int>(f); // C++20，编译期友好"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 联合体（需谨慎）\n",
    "\n",
    "旧式做法：通过 `union` 存储不同类型。但标准一直对此语焉不详，直到 C++20 才明确“读取非活跃成员”是未定义行为。部分厂商扩展允许这种行为，但可移植性较差。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 标准布局类型间的别名（标准仍有限制）\n",
    "\n",
    "若两个结构体是 **标准布局（standard-layout）**，且它们的初始布局完全相同，可以通过 `reinterpret_cast` 在它们之间转换并访问公共成员。这是非常细致的场景，需要对对象布局有充分把握。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 如何安全地“类型穿透”\n",
    "\n",
    "| 目的          | 推荐方式                                | 要点                            |\n",
    "| ------------- | --------------------------------------- | ------------------------------- |\n",
    "| 查看对象字节  | `std::byte` / `unsigned char`           | 合法，无别名风险                |\n",
    "| 类型转换      | `std::bit_cast<T>`                      | C++20 起首选，编译/运行期效率高 |\n",
    "| 老代码兼容    | `std::memcpy`                           | 适用于任何标准版本              |\n",
    "| 位字段技巧    | `std::bitset` 或 `std::span<std::byte>` | 避免直接 reinterpret_cast       |\n",
    "| SIMD/硬件接口 | `std::bit_cast` / 对齐的 `memcpy`       | 还需注意对齐、特定 ABI          |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 编译器选项与行为\n",
    "\n",
    "- GCC/Clang 默认开启 `-fstrict-aliasing`（在 `-O2` 及更高优化级别隐含）\n",
    "- 若使用 `-fno-strict-aliasing`，可关闭此优化假设，但一般不推荐（会减少优化空间）。\n",
    "- MSVC 的优化与标准不完全一致，但从 VS2015 起更趋向遵守标准。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 调试技巧\n",
    "\n",
    "1. **怀疑未定义行为**：如果优化级别越高问题越显著，考虑是否违反了 Strict Aliasing。\n",
    "2. **使用 UBSan**：`-fsanitize=undefined` 能捕获不少别名违规。\n",
    "3. **审查 reinterpret_cast**：逐个检查，确认类型别名关系是否被标准允许。\n",
    "4. **避免裸指针“互相假扮”**：从设计上减少不同类型指针指向同一内存的需求。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 小结\n",
    "\n",
    "- 严格别名是标准允许的激进优化假设。\n",
    "- 非法跨类型访问会触发未定义行为，在优化级别提高时尤为危险。\n",
    "- `std::bit_cast`（C++20）、`std::memcpy`、`std::byte` 是安全、高效的替代手段。\n",
    "- 理解并遵守 Strict Aliasing 规则，能让你的 C++ 代码更可靠，也便于编译器发挥性能潜力。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
